home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / srcuc.zip / UXPROC.C < prev    next >
C/C++ Source or Header  |  1992-03-26  |  23KB  |  796 lines

  1. /* -*-C-*-
  2.  
  3. $Header: /scheme/src/microcode/RCS/uxproc.c,v 1.14 1992/03/26 10:54:40 cph Exp $
  4.  
  5. Copyright (c) 1990-92 Massachusetts Institute of Technology
  6.  
  7. This material was developed by the Scheme project at the Massachusetts
  8. Institute of Technology, Department of Electrical Engineering and
  9. Computer Science.  Permission to copy this software, to redistribute
  10. it, and to use it for any purpose is granted, subject to the following
  11. restrictions and understandings.
  12.  
  13. 1. Any copy made of this software must include this copyright notice
  14. in full.
  15.  
  16. 2. Users of this software agree to make their best efforts (a) to
  17. return to the MIT Scheme project any improvements or extensions that
  18. they make, so that these may be included in future releases; and (b)
  19. to inform MIT of noteworthy uses of this software.
  20.  
  21. 3. All materials developed as a consequence of the use of this
  22. software shall duly acknowledge such use, in accordance with the usual
  23. standards of acknowledging credit in academic research.
  24.  
  25. 4. MIT has made no warrantee or representation that the operation of
  26. this software will be error-free, and MIT is under no obligation to
  27. provide any services, by way of maintenance, update, or otherwise.
  28.  
  29. 5. In conjunction with products arising from the use of this material,
  30. there shall be no use of the name of the Massachusetts Institute of
  31. Technology nor of any adaptation thereof in any advertising,
  32. promotional, or sales literature without prior written consent from
  33. MIT in each case. */
  34.  
  35. #include "ux.h"
  36. #include "uxproc.h"
  37. #include "uxio.h"
  38. #include "osterm.h"
  39.  
  40. #ifndef HAVE_DUP2
  41. #include "error: can't hack subprocess I/O without dup2() or equivalent"
  42. #endif
  43.  
  44. extern char ** environ;
  45. extern void EXFUN
  46.   ((*subprocess_death_hook), (pid_t pid, wait_status_t * status));
  47. extern void EXFUN ((*stop_signal_hook), (int signo));
  48. extern void EXFUN (stop_signal_default, (int signo));
  49. extern int EXFUN (OS_ctty_fd, (void));
  50.  
  51. static void EXFUN (subprocess_death, (pid_t pid, wait_status_t * status));
  52. static void EXFUN (stop_signal_handler, (int signo));
  53. static void EXFUN (give_terminal_to, (Tprocess process));
  54. static void EXFUN (get_terminal_back, (void));
  55. static void EXFUN (process_wait, (Tprocess process));
  56. static int EXFUN (child_setup_tty, (int fd));
  57.  
  58. size_t OS_process_table_size;
  59. struct process * process_table;
  60. enum process_jc_status scheme_jc_status;
  61.  
  62. static int scheme_ctty_fd;
  63. static Tprocess foreground_child_process;
  64.  
  65. static long process_tick;
  66. static long sync_tick;
  67.  
  68. #define NEW_RAW_STATUS(process, status, reason)                \
  69. {                                    \
  70.   (PROCESS_RAW_STATUS (process)) = (status);                \
  71.   (PROCESS_RAW_REASON (process)) = (reason);                \
  72.   (PROCESS_TICK (process)) = (++process_tick);                \
  73. }
  74.  
  75. #define PROCESS_STATUS_SYNC(process)                    \
  76. {                                    \
  77.   (PROCESS_STATUS (process)) = (PROCESS_RAW_STATUS (process));        \
  78.   (PROCESS_REASON (process)) = (PROCESS_RAW_REASON (process));        \
  79.   (PROCESS_SYNC_TICK (process)) = (PROCESS_TICK (process));        \
  80. }
  81.  
  82. /* This macro should only be used when
  83.    (scheme_jc_status == process_jc_status_jc). */
  84. #define SCHEME_IN_FOREGROUND()                        \
  85.   ((UX_tcgetpgrp (scheme_ctty_fd)) == (UX_getpgrp ()))
  86.  
  87. #ifdef HAVE_POSIX_SIGNALS
  88.  
  89. static void
  90. DEFUN (restore_signal_mask, (environment), PTR environment)
  91. {
  92.   UX_sigprocmask (SIG_SETMASK, ((sigset_t *) environment), 0);
  93. }
  94.  
  95. static void
  96. DEFUN_VOID (block_sigchld)
  97. {
  98.   sigset_t * outside = (dstack_alloc (sizeof (sigset_t)));
  99.   sigset_t sigchld;
  100.   UX_sigemptyset (&sigchld);
  101.   UX_sigaddset ((&sigchld), SIGCHLD);
  102.   UX_sigprocmask (SIG_BLOCK, (&sigchld), outside);
  103.   transaction_record_action (tat_always, restore_signal_mask, outside);
  104. }
  105.  
  106. static void
  107. DEFUN_VOID (block_jc_signals)
  108. {
  109.   sigset_t * outside = (dstack_alloc (sizeof (sigset_t)));
  110.   sigset_t jc_signals;
  111.   UX_sigemptyset (&jc_signals);
  112.   UX_sigaddset ((&jc_signals), SIGCHLD);
  113.   UX_sigaddset ((&jc_signals), SIGTTOU);
  114.   UX_sigaddset ((&jc_signals), SIGTTIN);
  115.   UX_sigaddset ((&jc_signals), SIGTSTP);
  116.   UX_sigaddset ((&jc_signals), SIGSTOP);
  117.   UX_sigprocmask (SIG_BLOCK, (&jc_signals), outside);
  118.   transaction_record_action (tat_always, restore_signal_mask, outside);
  119. }
  120.  
  121. static sigset_t grabbed_signal_mask;
  122.  
  123. static void
  124. DEFUN_VOID (grab_signal_mask)
  125. {
  126.   UX_sigprocmask (SIG_BLOCK, 0, (&grabbed_signal_mask));
  127. }
  128.  
  129. #else /* not HAVE_POSIX_SIGNALS */
  130.  
  131. #ifdef HAVE_SYSV3_SIGNALS
  132.  
  133. static void
  134. DEFUN (release_sigchld, (environment), PTR environment)
  135. {
  136.   UX_sigrelse (SIGCHLD);
  137. }
  138.  
  139. static void
  140. DEFUN_VOID (block_sigchld)
  141. {
  142.   UX_sighold (SIGCHLD);
  143.   transaction_record_action (tat_always, release_sigchld, 0);
  144. }
  145.  
  146. #else /* not HAVE_SYSV3_SIGNALS */
  147.  
  148. #define block_sigchld()
  149.  
  150. #endif /* not HAVE_SYSV3_SIGNALS */
  151.  
  152. #define block_jc_signals block_sigchld
  153. #define grab_signal_mask()
  154.  
  155. #endif /* not HAVE_POSIX_SIGNALS */
  156.  
  157. void
  158. DEFUN_VOID (UX_initialize_processes)
  159. {
  160.   OS_process_table_size = (UX_SC_CHILD_MAX ());
  161.   process_table =
  162.     (UX_malloc (OS_process_table_size * (sizeof (struct process))));
  163.   if (process_table == 0)
  164.     {
  165.       fprintf (stderr, "\nUnable to allocate process table.\n");
  166.       fflush (stderr);
  167.       termination_init_error ();
  168.     }
  169.   {
  170.     Tprocess process;
  171.     for (process = 0; (process < OS_process_table_size); process += 1)
  172.       OS_process_deallocate (process);
  173.   }
  174.   scheme_ctty_fd = (OS_ctty_fd ());
  175.   scheme_jc_status =
  176.     ((scheme_ctty_fd < 0)
  177.      ? process_jc_status_no_ctty
  178.      : (UX_SC_JOB_CONTROL ())
  179.      ? process_jc_status_jc
  180.      : process_jc_status_no_jc);
  181.   foreground_child_process = NO_PROCESS;
  182.   subprocess_death_hook = subprocess_death;
  183.   stop_signal_hook = stop_signal_handler;
  184.   process_tick = 0;
  185.   sync_tick = 0;
  186. }
  187.  
  188. void
  189. DEFUN_VOID (UX_reset_processes)
  190. {
  191.   UX_free (process_table);
  192.   process_table = 0;
  193.   OS_process_table_size = 0;
  194. }
  195.  
  196. static void
  197. DEFUN (process_allocate_abort, (environment), PTR environment)
  198. {
  199.   Tprocess process = (* ((Tprocess *) environment));
  200.   switch (PROCESS_RAW_STATUS (process))
  201.     {
  202.     case process_status_stopped:
  203.     case process_status_running:
  204.       UX_kill ((PROCESS_ID (process)), SIGKILL);
  205.       break;
  206.     }
  207.   OS_process_deallocate (process);
  208. }
  209.  
  210. static Tprocess
  211. DEFUN_VOID (process_allocate)
  212. {
  213.   Tprocess process;
  214.   for (process = 0; (process < OS_process_table_size); process += 1)
  215.     if ((PROCESS_RAW_STATUS (process)) == process_status_free)
  216.       {
  217.     Tprocess * pp = (dstack_alloc (sizeof (Tprocess)));
  218.     (*pp) = process;
  219.     transaction_record_action (tat_abort, process_allocate_abort, pp);
  220.     (PROCESS_RAW_STATUS (process)) = process_status_allocated;
  221.     return (process);
  222.       }
  223.   error_out_of_processes ();
  224.   return (NO_PROCESS);
  225. }
  226.  
  227. void
  228. DEFUN (OS_process_deallocate, (process), Tprocess process)
  229. {
  230.   (PROCESS_ID (process)) = 0;
  231.   (PROCESS_RAW_STATUS (process)) = process_status_free;
  232. }
  233.  
  234. Tprocess
  235. DEFUN (OS_make_subprocess,
  236.        (filename, argv, envp, working_directory,
  237.     ctty_type, ctty_name,
  238.     channel_in_type, channel_in,
  239.     channel_out_type, channel_out,
  240.     channel_err_type, channel_err),
  241.        CONST char * filename AND
  242.        char * CONST * argv AND
  243.        char * CONST * envp AND
  244.        CONST char * working_directory AND
  245.        enum process_ctty_type ctty_type AND
  246.        char * ctty_name AND
  247.        enum process_channel_type channel_in_type AND
  248.        Tchannel channel_in AND
  249.        enum process_channel_type channel_out_type AND
  250.        Tchannel channel_out AND
  251.        enum process_channel_type channel_err_type AND
  252.        Tchannel channel_err)
  253. {
  254.   pid_t child_pid;
  255.   Tprocess child;
  256.   enum process_jc_status child_jc_status;
  257.  
  258.   if (envp == 0)
  259.     envp = environ;
  260.   switch (ctty_type)
  261.     {
  262.     case process_ctty_type_none:
  263.       child_jc_status = process_jc_status_no_ctty;
  264.       break;
  265.     case process_ctty_type_explicit:
  266.       child_jc_status = process_jc_status_unrelated;
  267.       break;
  268.     case process_ctty_type_inherit_bg:
  269.     case process_ctty_type_inherit_fg:
  270.       child_jc_status = scheme_jc_status;
  271.       break;
  272.     }
  273.  
  274.   transaction_begin ();
  275.   child = (process_allocate ());
  276.  
  277.   /* Flush streams so that output won't be duplicated after the fork.  */
  278.   fflush (stdout);
  279.   fflush (stderr);
  280.  
  281.   grab_signal_mask ();
  282.   if (ctty_type == process_ctty_type_inherit_fg)
  283.     block_jc_signals ();
  284.   else
  285.     block_sigchld ();
  286.   STD_UINT_SYSTEM_CALL (syscall_vfork, child_pid, (UX_vfork ()));
  287.   if (child_pid > 0)
  288.     {
  289.       /* In the parent process. */
  290.       (PROCESS_ID (child)) = child_pid;
  291.       (PROCESS_JC_STATUS (child)) = child_jc_status;
  292.       (PROCESS_RAW_STATUS (child)) = process_status_running;
  293.       (PROCESS_RAW_REASON (child)) = 0;
  294.       (PROCESS_TICK (child)) = process_tick;
  295.       PROCESS_STATUS_SYNC (child);
  296.       if (child_jc_status == process_jc_status_jc)
  297.     STD_VOID_SYSTEM_CALL
  298.       (syscall_setpgid, (UX_setpgid (child_pid, child_pid)));
  299.       if (ctty_type == process_ctty_type_inherit_fg)
  300.     {
  301.       give_terminal_to (child);
  302.       process_wait (child);
  303.     }
  304.       transaction_commit ();
  305.       return (child);
  306.     }
  307.  
  308.   /* In the child process -- if any errors occur, just exit. */
  309.   /* Don't do `transaction_commit ()' here.  Because we used `vfork'
  310.      to spawn the child, the side-effects that are performed by
  311.      `transaction_commit' will occur in the parent as well. */
  312.   if (working_directory != 0)
  313.     UX_chdir (working_directory);
  314.   {
  315.     int in_fd = (-1);
  316.     int out_fd = (-1);
  317.     int err_fd = (-1);
  318.  
  319.     if (channel_in_type == process_channel_type_explicit)
  320.       in_fd = (CHANNEL_DESCRIPTOR (channel_in));
  321.     if (channel_out_type == process_channel_type_explicit)
  322.       out_fd = (CHANNEL_DESCRIPTOR (channel_out));
  323.     if (channel_err_type == process_channel_type_explicit)
  324.       err_fd = (CHANNEL_DESCRIPTOR (channel_err));
  325.  
  326.     if ((ctty_type == process_ctty_type_inherit_bg)
  327.     || (ctty_type == process_ctty_type_inherit_fg))
  328.       {
  329.     /* If the control terminal is inherited and job control is
  330.        available, force the child into a different process group. */
  331.     if (child_jc_status == process_jc_status_jc)
  332.       {
  333.         pid_t child_pid = (UX_getpid ());
  334.         if (((UX_setpgid (child_pid, child_pid)) < 0)
  335.         || ((ctty_type == process_ctty_type_inherit_fg)
  336.             && (SCHEME_IN_FOREGROUND ())
  337.             && ((UX_tcsetpgrp (scheme_ctty_fd, child_pid)) < 0)))
  338.           goto kill_child;
  339.       }
  340.       }
  341.     else
  342.       {
  343.     /* If the control terminal is not inherited, force the child
  344.        into a different session. */
  345.     if ((UX_setsid ()) < 0)
  346.       goto kill_child;
  347.     /* If the control terminal is explicit, open the given device
  348.        now so it becomes the control terminal. */
  349.     if (ctty_type == process_ctty_type_explicit)
  350.       {
  351.         int fd = (UX_open (ctty_name, O_RDWR, 0));
  352.         if ((fd < 0)
  353. #ifdef SLAVE_PTY_P
  354.         || ((SLAVE_PTY_P (ctty_name)) && (! (SETUP_SLAVE_PTY (fd))))
  355. #endif
  356.         || (! (isatty (fd)))
  357.         || ((child_setup_tty (fd)) < 0))
  358.           goto kill_child;
  359.         /* Use CTTY for standard I/O if requested. */
  360.         if (channel_in_type == process_channel_type_ctty)
  361.           in_fd = fd;
  362.         if (channel_out_type == process_channel_type_ctty)
  363.           out_fd = fd;
  364.         if (channel_err_type == process_channel_type_ctty)
  365.           err_fd = fd;
  366.       }
  367.       }
  368.  
  369.     /* Install the new standard I/O channels. */
  370.     if ((in_fd >= 0) && (in_fd != STDIN_FILENO))
  371.       {
  372.     if ((out_fd == STDIN_FILENO) && ((out_fd = (UX_dup (out_fd))) < 0))
  373.       goto kill_child;
  374.     if ((err_fd == STDIN_FILENO) && ((err_fd = (UX_dup (err_fd))) < 0))
  375.       goto kill_child;
  376.     if ((UX_dup2 (in_fd, STDIN_FILENO)) < 0)
  377.       goto kill_child;
  378.       }
  379.     if ((out_fd >= 0) && (out_fd != STDOUT_FILENO))
  380.       {
  381.     if ((err_fd == STDOUT_FILENO) && ((err_fd = (UX_dup (err_fd))) < 0))
  382.       goto kill_child;
  383.     if ((UX_dup2 (out_fd, STDOUT_FILENO)) < 0)
  384.       goto kill_child;
  385.       }
  386.     if ((err_fd >= 0) && (err_fd != STDERR_FILENO))
  387.       {
  388.     if ((UX_dup2 (err_fd, STDERR_FILENO)) < 0)
  389.       goto kill_child;
  390.       }
  391.   }
  392.   {
  393.     /* Close all other file descriptors. */
  394.     int fd = 0;
  395.     int open_max = (UX_SC_OPEN_MAX ());
  396.     while (fd < open_max)
  397.       {
  398.     if ((fd == STDIN_FILENO)
  399.         ? (channel_in_type == process_channel_type_none)
  400.         : (fd == STDOUT_FILENO)
  401.         ? (channel_out_type == process_channel_type_none)
  402.         : (fd == STDERR_FILENO)
  403.         ? (channel_err_type == process_channel_type_none)
  404.         : 1)
  405.       UX_close (fd);
  406.     fd += 1;
  407.       }
  408.   }
  409.  
  410.   /* Force the signal mask to be empty. */
  411. #ifdef HAVE_POSIX_SIGNALS
  412.   {
  413.     sigset_t empty_mask;
  414.     UX_sigemptyset (&empty_mask);
  415.     UX_sigprocmask (SIG_SETMASK, (&empty_mask), 0);
  416.   }
  417. #else
  418. #ifdef HAVE_SYSV3_SIGNALS
  419.   /* We could do something more here, but it is hard to enumerate all
  420.      the possible signals.  Instead, just release SIGCHLD, which we
  421.      know was held above before the child was spawned. */
  422.   UX_sigrelse (SIGCHLD);
  423. #endif
  424. #endif
  425.  
  426.   /* Start the process. */
  427.   execve (filename, argv, envp);
  428.  kill_child:
  429.   _exit (1);
  430. }
  431.  
  432. #define DEFUN_PROCESS_ACCESSOR(name, result_type, accessor)        \
  433. result_type                                \
  434. DEFUN (name, (process), Tprocess process)                \
  435. {                                    \
  436.   return (accessor (process));                        \
  437. }
  438.  
  439. DEFUN_PROCESS_ACCESSOR (OS_process_id, pid_t, PROCESS_ID)
  440. DEFUN_PROCESS_ACCESSOR (OS_process_status, enum process_status, PROCESS_STATUS)
  441. DEFUN_PROCESS_ACCESSOR (OS_process_reason, unsigned short, PROCESS_REASON)
  442. DEFUN_PROCESS_ACCESSOR
  443.   (OS_process_jc_status, enum process_jc_status, PROCESS_JC_STATUS)
  444.  
  445. int
  446. DEFUN (OS_process_valid_p, (process), Tprocess process)
  447. {
  448.   switch (PROCESS_RAW_STATUS (process))
  449.     {
  450.     case process_status_exited:
  451.     case process_status_signalled:
  452.     case process_status_stopped:
  453.     case process_status_running:
  454.       return (1);
  455.     default:
  456.       return (0);
  457.     }
  458. }
  459.  
  460. int
  461. DEFUN (OS_process_continuable_p, (process), Tprocess process)
  462. {
  463.   switch (PROCESS_RAW_STATUS (process))
  464.     {
  465.     case process_status_stopped:
  466.     case process_status_running:
  467.       return (1);
  468.     default:
  469.       return (0);
  470.     }
  471. }
  472.  
  473. int
  474. DEFUN (OS_process_foregroundable_p, (process), Tprocess process)
  475. {
  476.   switch (PROCESS_JC_STATUS (process))
  477.     {
  478.     case process_jc_status_no_jc:
  479.     case process_jc_status_jc:
  480.       return (1);
  481.     default:
  482.       return (0);
  483.     }
  484. }
  485.  
  486. int
  487. DEFUN (OS_process_status_sync, (process), Tprocess process)
  488. {
  489.   transaction_begin ();
  490.   block_sigchld ();
  491.   {
  492.     int result = ((PROCESS_TICK (process)) != (PROCESS_SYNC_TICK (process)));
  493.     if (result) PROCESS_STATUS_SYNC (process);
  494.     transaction_commit ();
  495.     return (result);
  496.   }
  497. }
  498.  
  499. int
  500. DEFUN_VOID (OS_process_status_sync_all)
  501. {
  502.   transaction_begin ();
  503.   block_sigchld ();
  504.   {
  505.     int result = (process_tick != sync_tick);
  506.     if (result) sync_tick = process_tick;
  507.     transaction_commit ();
  508.     return (result);
  509.   }
  510. }
  511.  
  512. int
  513. DEFUN_VOID (UX_process_any_status_change)
  514. {
  515.   return (process_tick != sync_tick);
  516. }
  517.  
  518. void
  519. DEFUN (OS_process_send_signal, (process, sig), Tprocess process AND int sig)
  520. {
  521.   STD_VOID_SYSTEM_CALL
  522.     (syscall_kill, 
  523.      (UX_kill ((((PROCESS_JC_STATUS (process)) == process_jc_status_jc)
  524.         ? (- (PROCESS_ID (process)))
  525.         : (PROCESS_ID (process))),
  526.            sig)));
  527. }
  528.  
  529. void
  530. DEFUN (OS_process_kill, (process), Tprocess process)
  531. {
  532.   OS_process_send_signal (process, SIGKILL);
  533. }
  534.  
  535. void
  536. DEFUN (OS_process_stop, (process), Tprocess process)
  537. {
  538.   OS_process_send_signal (process, SIGTSTP);
  539. }
  540.  
  541. void
  542. DEFUN (OS_process_interrupt, (process), Tprocess process)
  543. {
  544.   OS_process_send_signal (process, SIGINT);
  545. }
  546.  
  547. void
  548. DEFUN (OS_process_quit, (process), Tprocess process)
  549. {
  550.   OS_process_send_signal (process, SIGQUIT);
  551. }
  552.  
  553. void
  554. DEFUN (OS_process_hangup, (process), Tprocess process)
  555. {
  556.   OS_process_send_signal (process, SIGHUP);
  557. }
  558.  
  559. void
  560. DEFUN (OS_process_continue_background, (process), Tprocess process)
  561. {
  562.   transaction_begin ();
  563.   block_sigchld ();
  564.   if ((PROCESS_RAW_STATUS (process)) == process_status_stopped)
  565.     {
  566.       NEW_RAW_STATUS (process, process_status_running, 0);
  567.       OS_process_send_signal (process, SIGCONT);
  568.     }
  569.   transaction_commit ();
  570. }
  571.  
  572. void
  573. DEFUN (OS_process_continue_foreground, (process), Tprocess process)
  574. {
  575.   transaction_begin ();
  576.   grab_signal_mask ();
  577.   block_jc_signals ();
  578.   give_terminal_to (process);
  579.   if ((PROCESS_RAW_STATUS (process)) == process_status_stopped)
  580.     {
  581.       NEW_RAW_STATUS (process, process_status_running, 0);
  582.       OS_process_send_signal (process, SIGCONT); 
  583.     }
  584.   process_wait (process);
  585.   transaction_commit ();
  586. }
  587.  
  588. void
  589. DEFUN (OS_process_wait, (process), Tprocess process)
  590. {
  591.   transaction_begin ();
  592.   grab_signal_mask ();
  593.   block_jc_signals ();
  594.   process_wait (process);
  595.   transaction_commit ();
  596. }
  597.  
  598. static void
  599. DEFUN (get_terminal_back_1, (environment), PTR environment)
  600. {
  601.   get_terminal_back ();
  602. }
  603.  
  604. static void
  605. DEFUN (give_terminal_to, (process), Tprocess process)
  606. {
  607.   if (((PROCESS_JC_STATUS (process)) == process_jc_status_jc)
  608.       && (SCHEME_IN_FOREGROUND ()))
  609.     {
  610.       transaction_record_action (tat_always, get_terminal_back_1, 0);
  611.       foreground_child_process = process;
  612.       OS_save_internal_state ();
  613.       OS_restore_external_state ();
  614.       UX_tcsetpgrp (scheme_ctty_fd, (PROCESS_ID (process)));
  615.     }
  616. }
  617.  
  618. static void
  619. DEFUN_VOID (get_terminal_back)
  620. {
  621.   if (foreground_child_process != NO_PROCESS)
  622.     {
  623.       UX_tcsetpgrp (scheme_ctty_fd, (UX_getpgrp ()));
  624.       OS_save_external_state ();
  625.       OS_restore_internal_state ();
  626.       foreground_child_process = NO_PROCESS;
  627.     }
  628. }
  629.  
  630. static void
  631. DEFUN (process_wait, (process), Tprocess process)
  632. {
  633. #ifdef HAVE_POSIX_SIGNALS
  634.   while (((PROCESS_RAW_STATUS (process)) == process_status_running)
  635.      && (! (pending_interrupts_p ())))
  636.     UX_sigsuspend (&grabbed_signal_mask);
  637. #else /* not HAVE_POSIX_SIGNALS */
  638.   enum process_status status = (PROCESS_RAW_STATUS (process));
  639.   while ((status == process_status_running)
  640.      && (! (pending_interrupts_p ())))
  641.     {
  642.       /* INTERRUPTABLE_EXTENT eliminates the interrupt window between
  643.      PROCESS_RAW_STATUS and `pause'. */
  644.       int scr;
  645.       INTERRUPTABLE_EXTENT
  646.     (scr,
  647.      ((((status = (PROCESS_RAW_STATUS (process)))
  648.         == process_status_running)
  649.        && (! (pending_interrupts_p ())))
  650.       ? (UX_pause ())
  651.       : ((errno = EINTR), (-1))));
  652.     }
  653. #endif /* not HAVE_POSIX_SIGNALS */
  654. }
  655.  
  656. static Tprocess
  657. DEFUN (find_process, (pid), pid_t pid)
  658. {
  659.   Tprocess process;
  660.   for (process = 0; (process < OS_process_table_size); process += 1)
  661.     if ((PROCESS_ID (process)) == pid)
  662.       return (process);
  663.   return (NO_PROCESS);
  664. }
  665.  
  666. static void
  667. DEFUN (subprocess_death, (pid, status), pid_t pid AND wait_status_t * status)
  668. {
  669.   Tprocess process = (find_process (pid));
  670.   if (process != NO_PROCESS)
  671.     {
  672.       if (WIFEXITED (*status))
  673.     {
  674.       NEW_RAW_STATUS
  675.         (process, process_status_exited, (WEXITSTATUS (*status)));
  676.     }
  677.       else if (WIFSTOPPED (*status))
  678.     {
  679.       NEW_RAW_STATUS
  680.         (process, process_status_stopped, (WSTOPSIG (*status)));
  681.     }
  682.       else if (WIFSIGNALED (*status))
  683.     {
  684.       NEW_RAW_STATUS
  685.         (process, process_status_signalled, (WTERMSIG (*status)));
  686.     }
  687.     }
  688. }
  689.  
  690. static void
  691. DEFUN (stop_signal_handler, (signo), int signo)
  692. {
  693.   /* If Scheme gets a stop signal while waiting on a foreground
  694.      subprocess, it must grab the terminal back from the subprocess
  695.      before stopping.  The caller guarantees that the job-control
  696.      signals are blocked when this procedure is called. */
  697.   get_terminal_back ();
  698.   stop_signal_default (signo);
  699. }
  700.  
  701. /* Set up the terminal at the other end of a pseudo-terminal that we
  702.    will be controlling an inferior through. */
  703.  
  704. #ifdef HAVE_TERMIOS
  705.  
  706. #ifndef IUCLC
  707. /* POSIX.1 doesn't require (or even mention) these symbols, but we
  708.    must disable them if they are present. */
  709. #define IUCLC 0
  710. #define OLCUC 0
  711. #define ONLCR 0
  712. #define NLDLY 0
  713. #define CRDLY 0
  714. #define TABDLY 0
  715. #define BSDLY 0
  716. #define VTDLY 0
  717. #define FFDLY 0
  718. #endif
  719.  
  720. static int
  721. DEFUN (child_setup_tty, (fd), int fd)
  722. {
  723.   cc_t disabled_char = (UX_PC_VDISABLE (fd));
  724.   struct termios s;
  725.   if ((UX_tcgetattr (fd, (&s))) < 0)
  726.     return (-1);
  727.   (s . c_iflag) &=~ IUCLC;
  728.   (s . c_oflag) |= OPOST;
  729.   (s . c_oflag) &=~
  730.     (OLCUC | ONLCR | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
  731.   (s . c_lflag) &=~ (ECHO | ECHOE | ECHOK | ECHONL);
  732.   (s . c_lflag) |= (ICANON | ISIG);
  733.   ((s . c_cc) [VEOF]) = '\004';
  734.   ((s . c_cc) [VERASE]) = disabled_char;
  735.   ((s . c_cc) [VKILL]) = disabled_char;
  736.   cfsetispeed ((&s), B9600);
  737.   cfsetospeed ((&s), B9600);
  738.   return (UX_tcsetattr (fd, TCSADRAIN, (&s)));
  739. }
  740.  
  741. #else /* not HAVE_TERMIOS */
  742.  
  743. #ifdef HAVE_TERMIO
  744.  
  745. static int
  746. DEFUN (child_setup_tty, (fd), int fd)
  747. {
  748.   cc_t disabled_char = (UX_PC_VDISABLE (fd));
  749.   struct termio s;
  750.   if ((ioctl (fd, TCGETA, (&s))) < 0)
  751.     return (-1);
  752.   (s . c_iflag) &=~ IUCLC;
  753.   (s . c_oflag) |= OPOST;
  754.   (s . c_oflag) &=~
  755.     (OLCUC | ONLCR | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
  756.   (s . c_lflag) &=~ (ECHO | ECHOE | ECHOK | ECHONL);
  757.   (s . c_lflag) |= (ICANON | ISIG);
  758.   ((s . c_cc) [VEOF]) = '\004';
  759.   ((s . c_cc) [VERASE]) = disabled_char;
  760.   ((s . c_cc) [VKILL]) = disabled_char;
  761.   (s . c_cflag) = (((s . c_cflag) &~ CBAUD) | B9600);
  762. #ifdef _AIX
  763.   /* AIX enhanced edit loses NULs, so disable it.
  764.      Also, PTY overloads NUL and BREAK.
  765.      don't ignore break, but don't signal either, so it looks like NUL.
  766.      This really serves a purpose only if running in an XTERM window
  767.      or via TELNET or the like, but does no harm elsewhere.  */
  768.   (s . c_line) = 0;
  769.   (s . c_iflag) &=~ (ASCEDIT | IGNBRK | BRKINT);
  770.   /* QUIT and INTR work better as signals, so disable character forms */
  771.   (s . c_lflag) &=~ ISIG;
  772.   ((s . c_cc) [VQUIT]) = disabled_char;
  773.   ((s . c_cc) [VINTR]) = disabled_char;
  774.   ((s . c_cc) [VEOL]) = disabled_char;
  775. #endif /* _AIX */
  776.   return (ioctl (fd, TCSETAW, (&s)));
  777. }
  778.  
  779. #else /* not HAVE_TERMIO */
  780. #ifdef HAVE_BSD_TTY_DRIVER
  781.  
  782. static int
  783. DEFUN (child_setup_tty, (fd), int fd)
  784. {
  785.   struct sgttyb s;
  786.   if ((ioctl (fd, TIOCGETP, (&s))) < 0)
  787.     return (-1);
  788.   (s . sg_flags) &=~
  789.     (ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE | CBREAK | TANDEM);
  790.   return (ioctl (fd, TIOCSETN, (&s)));
  791. }
  792.  
  793. #endif /* HAVE_BSD_TTY_DRIVER */
  794. #endif /* HAVE_TERMIO */
  795. #endif /* HAVE_TERMIOS */
  796.